﻿var bee = {
    keyCode: {
        ENTER: 13, ESC: 27, END: 35, HOME: 36,
        SHIFT: 16, TAB: 9,
        LEFT: 37, RIGHT: 39, UP: 38, DOWN: 40,
        DELETE: 46, BACKSPACE: 8
    },
    ui: { sbar: true },
    frag: {},
    _msg: {},
    jsonEval: function(json) {
        try {
            if ($.type(json) == 'string')
                return eval('(' + json + ')');
            else return json;
        } catch (e) {
            return {};
        }
    },
    _set: {
        loginUrl: "", //session timeout
        loginTitle: "", //if loginTitle open a login dialog
        debug: true
    },
    debug: function(msg) {
        if (this._set.debug) {
            if (typeof (console) != "undefined") console.log(msg);
            else alert(msg);
        }
    },
    msg: function(key, args) {
        var _format = function(str, args) {
            args = args || [];
            var result = str || "";
            for (var i = 0; i < args.length; i++) {
                result = result.replace(new RegExp("\\{" + i + "\\}", "g"), args[i]);
            }
            return result;
        }
        return _format(this._msg[key], args);
    },
    ajaxError: function(xhr, ajaxOptions, thrownError) {
        if (alertMsg) {
            alertMsg.error("<div>Http status: " + xhr.status + " " + xhr.statusText + "</div>"
				+ "<div>ajaxOptions: " + ajaxOptions + "</div>"
				+ "<div>thrownError: " + thrownError + "</div>"
				+ "<div>" + xhr.responseText + "</div>");
        } else {
            alert("Http status: " + xhr.status + " " + xhr.statusText + "\najaxOptions: " + ajaxOptions + "\nthrownError:" + thrownError + "\n" + xhr.responseText);
        }
    },
    ajaxDone: function(json) {
        if (json.status) {
            if (json.message && alertMsg) alertMsg.correct(json.message);
        } else {
            if (json.message && alertMsg) alertMsg.error(json.message);
        }
    },
    isOverAxis: function(x, reference, size) {
        //Determines when x coordinate is over "b" element axis
        return (x > reference) && (x < (reference + size));
    },
    isOver: function(y, x, top, left, height, width) {
        //Determines when x, y coordinates is over "b" element
        return this.isOverAxis(y, top, height) && this.isOverAxis(x, left, width);
    },
    init: function(options) {
        var op = $.extend({ callback: null, debug: false }, options);
        jQuery.ajax({
            type: 'GET',
            url: "/js/bee.html.xml",
            dataType: 'xml',
            timeout: 50000,
            cache: false,
            error: function(xhr) {
                alert('Error loading XML document: ' + pageFrag + "\nHttp status: " + xhr.status + " " + xhr.statusText);
            },
            success: function(xml) {
                $(xml).find("_PAGE_").each(function() {
                    var pageId = $(this).attr("id");
                    if (pageId) bee.frag[pageId] = $(this).text();
                });

                $(xml).find("_MSG_").each(function() {
                    var id = $(this).attr("id");
                    if (id) bee._msg[id] = $(this).text();
                });

                if (jQuery.isFunction(op.callback)) op.callback();
            }
        });
        $(":text.number").live("change", function() {
            var $this = $(this);
            var format = $this.attr("format");
            var value = $this.val();

            if (value.indexOf('.') > 0) {
                if (format == 'none') return;
                if (format == undefined) {
                    format = 2;
                }
                $this.val($this.val().formatNumber(format));
            }
        });
    },
    PostData: function(service, para, successFunction) {
        var $callback = successFunction;
        if (!$.isFunction($callback)) $callback = eval('(' + successFunction + ')');
        $.ajax({
            type: "post",
            url: service,
            data: para,
            global: false,
            cache: false,
            dataType: "json",
            success: function(json) {
                if (!json.status) {
                    if (json.message && alertMsg) alertMsg.error(json.message);
                    if (json.tologin) {
                        toLogin();
                    }
                }
                else {
                    if ($.isFunction($callback)) {
                        $callback(json.result);
                    }
                }
            },
            error: bee.ajaxError
        });
    },
    initUI: function(_box) {

        var $p = $(_box || document);
        if ($.fn.jPanel) {
            $("div.panel", $p).jPanel();
        }
        if ($.fn.widget) {
            $("div.widget", $p).each(function() {
                var $this = $(this);
                $this.widget({ collapsible: !$this.hasClass("noCollape"), removable: !$this.hasClass("noRemove") });
            });
        }

        $('div.accordion', $p).each(function() {
            var $this = $(this);
            $this.accordion({ fillSpace: $this.attr("fillSpace"), alwaysOpen: false, active: 0 });
        });

        //tables
        if ($.fn.jTable) $("table.table", $p).jTable();
        if ($.fn.cssTable) $("table.list", $p).cssTable();
        if ($.fn.tabs) $("div.tabs", $p).each(function() {
            var $this = $(this);
            var options = {};
            options.currentIndex = $this.attr("currentIndex") || 0;
            options.eventType = $this.attr("eventType") || "click";
            $this.tabs(options);
        });

        if ($.fn.jBar) $("#leftside", $p).jBar({ minW: 150, maxW: 700 });
        if ($.fn.jTree) $("ul.tree", $p).jTree();

        $("input[type=text], input[type=password], textarea", $p).addClass("textInput").focusClass("focus");



        $("input[readonly], textarea[readonly]", $p).addClass("readonly");
        $("input[disabled=true], textarea[disabled=true]", $p).addClass("disabled");
        $("form", $p).keypress(function(event) {
            if (event.keyCode == bee.keyCode.ENTER) {
                //autoSave($(this).attr("Id"));
                return false;
            }
        });

        if ($.fn.combox) $("select.combox", $p).combox();
        if ($.fn.jtip) $(".tip", $p).jtip();

        if ($.fn.checkboxCtrl) $(":button.checkboxCtrl, :checkbox.checkboxCtrl", $p).checkboxCtrl($p);

        if ($.fn.datepicker) {
            $('input.date', $p).each(function() {
                var $this = $(this);
                var opts = {};
                if ($this.attr("dateFmt")) opts.pattern = $this.attr("dateFmt");
                if ($this.attr("minDate")) opts.minDate = $this.attr("minDate");
                if ($this.attr("maxDate")) opts.maxDate = $this.attr("maxDate");
                if ($this.attr("mmStep")) opts.mmStep = $this.attr("mmStep");
                if ($this.attr("ssStep")) opts.ssStep = $this.attr("ssStep");
                $this.datepicker(opts);
            });
        }

        $("form.required-validate", $p).each(function() {
            var $form = $(this);
            $form.validate({
                focusInvalid: false,
                focusCleanup: true,
                errorElement: "span",
                ignore: ".ignore",
                showErrors: function() {
                    var idValue = $form.attr("id");
                    if ($form.hasClass("alertMsg")) {
                        validShowAlertMsgError(this);
                    }
                    else {
                        this.defaultShowErrors();
                    }
                }

            });
        });

        if (navTab) navTab.init();

        $("div.pagination", $p).each(function() {
            var $this = $(this);
            $this.pagination({
                targetType: $this.attr("targetType"),
                totalCount: $this.attr("totalCount"),
                numPerPage: $this.attr("numPerPage"),
                pageNumShown: $this.attr("pageNumShown"),
                currentPage: $this.attr("currentPage"),
                href: $this.attr("href"),
                click: $this.attr("click")
            });
        });

        $("a[target=navTab]", $p).each(function() {
            $(this).click(function(event) {
                var $this = $(this);
                var title = $this.attr("title") || $this.text();
                var tabid = $this.attr("rel") || "_blank";
                var fresh = eval($this.attr("fresh") || "true");
                var external = eval($this.attr("external") || "false");
                var url = unescape($this.attr("href"));
                if (!url.isFinishedTm()) {
                    alertMsg.error($this.attr("warn"));
                    return false;
                }
                navTab.openTab(tabid, url, { title: title, fresh: fresh, external: external });

                event.preventDefault();
            });
        });

        // 浏览器窗口打开
        $("a[target=bdialog]", $p).each(function() {
            $(this).click(function(event) {
                var $this = $(this);
                var title = $this.attr("title") || $this.text();

                var w = $this.attr("width");
                var h = $this.attr("height");
                var url = unescape($this.attr("href")).replaceTmById($p);
                if (!url.isFinishedTm()) {
                    alertMsg.error($this.attr("warn"));
                    return false;
                }
                if (!w) {
                    w = 800;
                }
                if (!h) {
                    h = 600;
                }

                event.preventDefault();

                window.open(url, title, 'height=' + h + ',width=' + w + ',top=100,left=150,toolbar=no,menubar=no,scrollbars=yes,resizable=yes, location=no,status=no')


            });
        });

        if ($.fn.jtip) {
            $("a[target=tip],a[target=imgtip]", $p).each(function() {
                $(this).attr("title", "");
                $(this).jtip();

                $(this).click(function(event) {
                    event.preventDefault();
                });
            });
        }


        //dialogs
        $("a[target=dialog]", $p).each(function() {
            $(this).click(function(event) {
                var $this = $(this);
                var title = $this.attr("title") || $this.text();
                var rel = $this.attr("rel") || "_blank";
                var options = {};
                var w = $this.attr("width");
                var h = $this.attr("height");
                if (w) options.width = w;
                if (h) options.height = h;
                options.max = eval($this.attr("max") || "false");
                options.mask = eval($this.attr("mask") || "false");
                options.maxable = eval($this.attr("maxable") || "false");
                options.minable = eval($this.attr("minable") || "false");
                options.fresh = eval($this.attr("fresh") || "true");
                options.resizable = eval($this.attr("resizable") || "true");
                options.drawable = eval($this.attr("drawable") || "true");
                options.close = eval($this.attr("close") || "");
                options.param = $this.attr("param") || "";

                var url = unescape($this.attr("href")).replaceTmById($p);
                if (!url.isFinishedTm()) {
                    alertMsg.error($this.attr("warn"));
                    return false;
                }
                $.pdialog.open(url, rel, title, options);

                return false;
            });
        });

        $("a[target=ajaxTodo]", $p).each(function() {
            $(this).click(function(event) {
                var $this = $(this);
                var url = unescape($this.attr("href"));

                var title = $this.attr("title");
                if (title) {
                    alertMsg.confirm(title, {
                        okCall: function() {
                            ajaxTodo(url, $this.attr("callback"));
                        }
                    });
                } else {
                    ajaxTodo(url, $this.attr("callback"));
                }
                event.preventDefault();
            });
        });

        if ($.fn.uploadify) {
            $(":file[uploaderOption]", $p).each(function() {
                var $this = $(this);
                var options = {
                    fileObjName: $this.attr("name") || "file",
                    auto: true,
                    multi: true,
                    onUploadError: uploadifyError
                };

                var uploaderOption = bee.jsonEval($this.attr("uploaderOption"));
                $.extend(options, uploaderOption);

                $this.uploadify(options);
            });
        }

        if ($.fn.tagsInput) {
            $("input[tagsInputOption]", $p).each(function() {
                var $this = $(this);
                var options = { defaultText: "添加标签" };
                var uploaderOption = bee.jsonEval($this.attr("tagsInputOption"));
                $.extend(options, uploaderOption);

                $this.tagsInput(options);
            });
        }

        if ($.fn.xheditor) {
            $("textarea.editor", $p).each(function() {
                var $this = $(this);
                var op = { html5Upload: false, skin: 'vista', tools: $this.attr("tools") || 'full' };
                var upAttrs = [
				["upLinkUrl", "upLinkExt", "zip,rar,txt"],
				["upImgUrl", "upImgExt", "jpg,jpeg,gif,png"],
				["upFlashUrl", "upFlashExt", "swf"],
				["upMediaUrl", "upMediaExt", "avi"]
			];

                $(upAttrs).each(function(i) {
                    var urlAttr = upAttrs[i][0];
                    var extAttr = upAttrs[i][1];

                    if ($this.attr(urlAttr)) {
                        op[urlAttr] = $this.attr(urlAttr);
                        op[extAttr] = $this.attr(extAttr) || upAttrs[i][2];
                    }
                });

                $this.xheditor(op);
            });
        }

        if ($.fn.sortDrag) $("div.sortDrag, ul.sortDrag", $p).sortDrag();
        if ($.fn.itemDetail) $("table.itemDetail", $p).itemDetail();
        if ($.fn.suggest) $("input[suggestFields]", $p).suggest();
        if ($.fn.lookup) $("a[lookupGroup]", $p).lookup();
        if ($.fn.multLookup) $("a[multLookup]", $p).multLookup();


    }

};

if ($.validator) {
    $.extend($.validator.messages, {
        required: "必填字段",
        remote: "请修正该字段",
        email: "请输入正确格式的电子邮件",
        url: "请输入合法的网址",
        date: "请输入合法的日期",
        dateISO: "请输入合法的日期 (ISO).",
        number: "请输入合法的数字",
        digits: "只能输入整数",
        creditcard: "请输入合法的信用卡号",
        equalTo: "请再次输入相同的值",
        accept: "请输入拥有合法后缀名的字符串",
        maxlength: $.validator.format("长度最多是 {0} 的字符串"),
        minlength: $.validator.format("长度最少是 {0} 的字符串"),
        rangelength: $.validator.format("长度介于 {0} 和 {1} 之间的字符串"),
        range: $.validator.format("请输入一个介于 {0} 和 {1} 之间的值"),
        max: $.validator.format("请输入一个最大为 {0} 的值"),
        min: $.validator.format("请输入一个最小为 {0} 的值"),

        alphanumeric: "字母、数字、下划线",
        lettersonly: "必须是字母",
        phone: "数字、空格、括号"
    });
}

(function($) {
    $.setRegional = function(key, value) {
        if (!$.regional) $.regional = {};
        $.regional[key] = value;
    };

    $.fn.extend({
        cookie: function(name, value, options) {
            if (typeof value != 'undefined') { // name and value given, set cookie
                options = options || {};
                if (value === null) {
                    value = '';
                    options.expires = -1;
                }
                var expires = '';
                if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
                    var date;
                    if (typeof options.expires == 'number') {
                        date = new Date();
                        date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
                    } else {
                        date = options.expires;
                    }
                    expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
                }
                var path = options.path ? '; path=' + options.path : '';
                var domain = options.domain ? '; domain=' + options.domain : '';
                var secure = options.secure ? '; secure' : '';
                document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
            } else { // only name given, get cookie
                var cookieValue = null;
                if (document.cookie && document.cookie != '') {
                    var cookies = document.cookie.split(';');
                    for (var i = 0; i < cookies.length; i++) {
                        var cookie = jQuery.trim(cookies[i]);
                        // Does this cookie string begin with the name we want?
                        if (cookie.substring(0, name.length + 1) == (name + '=')) {
                            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                            break;
                        }
                    }
                }
                return cookieValue;
            }
        },
        ajaxUrl: function(op) {
            var $this = $(this);
            $.ajax({
                type: op.type || 'GET',
                url: op.url,
                data: op.data,
                cache: false,
                success: function(response) {
                    var json = bee.jsonEval(response);
                    if (json.status != undefined) {
                        if (!json.status) {
                            alertMsg.error(json.message);
                            if (json.tologin) {
                                toLogin();
                            }
                        }
                        else {
                            $this.html(json.result); bee.initUI($this);
                        }
                    }
                    else {
                        $this.html(response); bee.initUI($this);
                    }
                    if (op.callback) {
                        if ($.isFunction(op.callback)) op.callback(response);
                    }
                },
                error: bee.ajaxError
            });
        },
        loadUrl: function(url, data, callback) {
            $(this).ajaxUrl({ url: url, data: data, callback: callback });
        },
        initUI: function() {
            return this.each(function() {
                bee.initUI(this);
            });
        },
        /**
        * adjust component inner reference box height
        * @param {Object} refBox: reference box jQuery Obj
        */
        layoutH: function($refBox) {
            return this.each(function() {
                var $this = $(this);
                if (!$refBox) $refBox = ("dialog" == $this.attr("layoutType") && $.pdialog) ? $.pdialog.getCurrent().find(".dialogContent") : $("#container .tabsPageContent");
                var iRefH = $refBox.height();
                var iLayoutH = parseInt($this.attr("layoutH"));
                var iH = iRefH - iLayoutH > 50 ? iRefH - iLayoutH : 50;

                if ($this.isTag("table")) {
                    $this.removeAttr("layoutH").wrap('<div layoutH="' + iLayoutH + '" style="overflow:auto;height:' + iH + 'px"></div>');
                } else {
                    $this.height(iH).css("overflow", "auto");
                }
            });
        },
        hoverClass: function(className) {
            var _className = className || "hover";
            return this.each(function() {
                $(this).hover(function() {
                    $(this).addClass(_className);
                }, function() {
                    $(this).removeClass(_className);
                });
            });
        },
        focusClass: function(className) {
            var _className = className || "textInputFocus";
            return this.each(function() {
                $(this).focus(function() {
                    $(this).addClass(_className);
                }).blur(function() {
                    $(this).removeClass(_className);
                });
            });
        },
        inputAlert: function() {
            return this.each(function() {

                var $this = $(this);

                function getAltBox() {
                    return $this.parent().find("label.alt");
                }
                function altBoxCss(opacity) {
                    var position = $this.position();
                    return {
                        width: $this.width(),
                        top: position.top + 'px',
                        left: position.left + 'px',
                        opacity: opacity || 1
                    }
                }
                if (getAltBox().size() < 1) {
                    if (!$this.attr("id")) $this.attr("id", $this.attr("name") + "_" + Math.round(Math.random() * 10000));
                    var $label = $('<label class="alt" for="' + $this.attr("id") + '">' + $this.attr("alt") + '</label>').appendTo($this.parent());

                    $label.css(altBoxCss(1));
                    if ($this.val()) $label.hide();
                }

                $this.focus(function() {
                    getAltBox().css(altBoxCss(0.3));
                }).blur(function() {
                    if (!$(this).val()) getAltBox().show().css("opacity", 1);
                }).keydown(function() {
                    getAltBox().hide();
                });
            });
        },
        isTag: function(tn) {
            if (!tn) return false;
            return $(this)[0].tagName.toLowerCase() == tn ? true : false;
        }
    });

    /**
    * 扩展String方法
    */
    $.extend(String.prototype, {
        isPositiveInteger: function() {
            return (new RegExp(/^[1-9]\d*$/).test(this));
        },
        isInteger: function() {
            return (new RegExp(/^\d+$/).test(this));
        },
        isNumber: function(value, element) {
            return (new RegExp(/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/).test(this));
        },
        trim: function() {
            return this.replace(/(^\s*)|(\s*$)|\r|\n/g, "");
        },
        compareIgnoreCase: function(value) {
            return this.toLowerCase() == value.toLowerCase();
        },
        startsWith: function(pattern) {
            return this.indexOf(pattern) === 0;
        },
        endsWith: function(pattern) {
            var d = this.length - pattern.length;
            return d >= 0 && this.lastIndexOf(pattern) === d;
        },
        replaceSuffix: function(index) {
            return this.replace(/\[[0-9]+\]/, '[' + index + ']').replace('#index#', index);
        },
        trans: function() {
            return this.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"');
        },
        replaceForId: function() {
            return this.replace(new RegExp("([\\[\\]\\.]+?)", "gm"), "\\$1");
        },
        replaceAll: function(os, ns) {
            return this.replace(new RegExp(os, "igm"), ns);
        },
        replaceTm: function($data) {
            if (!$data) return this;
            return this.replace(RegExp("({[A-Za-z_]+[A-Za-z0-9_]*})", "g"), function($1) {
                return $data[$1.replace(/[{}]+/g, "")];
            });
        },
        replaceTmById: function(_box) {
            var $parent = _box || $(document);
            return this.replace(RegExp("({[A-Za-z_]+[A-Za-z0-9_\\.\\[\\]]*})", "g"), function($1) {
                var name = $1.replace(/[{}]+/g, "");
                name = name.replaceForId();
                var $input = $parent.find("#" + name);
                if ($input.length) {
                    return $input.val();
                }
                else {
                    $input = $parent.find("input[name=" + name + "], select[name=" + name + "]");
                    if ($input.length) {
                        return $input.val();
                    }
                }
                return ""; // 没有就为空
            });
        },
        isFinishedTm: function() {
            return !(new RegExp("{[A-Za-z_]+[A-Za-z0-9_]*}").test(this));
        },
        skipChar: function(ch) {
            if (!this || this.length === 0) { return ''; }
            if (this.charAt(0) === ch) { return this.substring(1).skipChar(ch); }
            return this;
        },
        isValidPwd: function() {
            return (new RegExp(/^([_]|[a-zA-Z0-9]){6,32}$/).test(this));
        },
        isValidMail: function() {
            return (new RegExp(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/).test(this.trim()));
        },
        isSpaces: function() {
            for (var i = 0; i < this.length; i += 1) {
                var ch = this.charAt(i);
                if (ch != ' ' && ch != "\n" && ch != "\t" && ch != "\r") { return false; }
            }
            return true;
        },
        isPhone: function() {
            return (new RegExp(/(^([0-9]{3,4}[-])?\d{3,8}(-\d{1,6})?$)|(^\([0-9]{3,4}\)\d{3,8}(\(\d{1,6}\))?$)|(^\d{3,8}$)/).test(this));
        },
        isUrl: function() {
            return (new RegExp(/^[a-zA-z]+:\/\/([a-zA-Z0-9\-\.]+)([-\w .\/?%&=:]*)$/).test(this));
        },
        isExternalUrl: function() {
            return this.isUrl() && this.indexOf("://" + document.domain) == -1;
        },
        formatNumber: function(format) {

            //decimals, dec_point, thousands_sep
            var decimals = parseInt(format);
            var number = (this + '').replace(/[^0-9+-Ee.]/g, '');
            var n = !isFinite(+number) ? 0 : +number,
            prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
            sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
            dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
            s = '',
            toFixedFix = function(n, prec) {
                var k = Math.pow(10, prec);
                return '' + Math.round(n * k) / k;
            };
            // Fix for IE parseFloat(0.55).toFixed(0) = 0;
            s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
            if (s[0].length > 3) {
                s[0] = s[0].replace(/B(?=(?:d{3})+(?!d))/g, sep);
            }
            if ((s[1] || '').length < prec) {
                s[1] = s[1] || '';
                s[1] += new Array(prec - s[1].length + 1).join('0');
            }
            return s.join(dec);
        }
    });
})(jQuery);

/** 
* You can use this map like this:
* var myMap = new Map();
* myMap.put("key","value");
* var key = myMap.get("key");
* myMap.remove("key");
*/
function Map() {

    this.elements = new Array();

    this.size = function() {
        return this.elements.length;
    }

    this.isEmpty = function() {
        return (this.elements.length < 1);
    }

    this.clear = function() {
        this.elements = new Array();
    }

    this.put = function(_key, _value) {
        this.remove(_key);
        this.elements.push({ key: _key, value: _value });
    }

    this.remove = function(_key) {
        try {
            for (i = 0; i < this.elements.length; i++) {
                if (this.elements[i].key == _key) {
                    this.elements.splice(i, 1);
                    return true;
                }
            }
        } catch (e) {
            return false;
        }
        return false;
    }

    this.get = function(_key) {
        try {
            for (i = 0; i < this.elements.length; i++) {
                if (this.elements[i].key == _key) { return this.elements[i].value; }
            }
        } catch (e) {
            return null;
        }
    }

    this.element = function(_index) {
        if (_index < 0 || _index >= this.elements.length) { return null; }
        return this.elements[_index];
    }

    this.containsKey = function(_key) {
        try {
            for (i = 0; i < this.elements.length; i++) {
                if (this.elements[i].key == _key) {
                    return true;
                }
            }
        } catch (e) {
            return false;
        }
        return false;
    }

    this.values = function() {
        var arr = new Array();
        for (i = 0; i < this.elements.length; i++) {
            arr.push(this.elements[i].value);
        }
        return arr;
    }

    this.keys = function() {
        var arr = new Array();
        for (i = 0; i < this.elements.length; i++) {
            arr.push(this.elements[i].key);
        }
        return arr;
    }
}


(function() {
    var MONTH_NAMES = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
    var DAY_NAMES = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
    function LZ(x) { return (x < 0 || x > 9 ? "" : "0") + x }

    /**
    * formatDate (date_object, format)
    * Returns a date in the output format specified.
    * The format string uses the same abbreviations as in parseDate()
    * @param {Object} date
    * @param {Object} format
    */
    function formatDate(date, format) {
        format = format + "";
        var result = "";
        var i_format = 0;
        var c = "";
        var token = "";
        var y = date.getYear() + "";
        var M = date.getMonth() + 1;
        var d = date.getDate();
        var E = date.getDay();
        var H = date.getHours();
        var m = date.getMinutes();
        var s = date.getSeconds();
        var yyyy, yy, MMM, MM, dd, hh, h, mm, ss, ampm, HH, H, KK, K, kk, k;
        // Convert real date parts into formatted versions
        var value = {};
        if (y.length < 4) { y = "" + (y - 0 + 1900); }
        value["y"] = "" + y;
        value["yyyy"] = y;
        value["yy"] = y.substring(2, 4);
        value["M"] = M;
        value["MM"] = LZ(M);
        value["MMM"] = MONTH_NAMES[M - 1];
        value["NNN"] = MONTH_NAMES[M + 11];
        value["d"] = d;
        value["dd"] = LZ(d);
        value["E"] = DAY_NAMES[E + 7];
        value["EE"] = DAY_NAMES[E];
        value["H"] = H;
        value["HH"] = LZ(H);
        if (H == 0) { value["h"] = 12; }
        else if (H > 12) { value["h"] = H - 12; }
        else { value["h"] = H; }
        value["hh"] = LZ(value["h"]);
        if (H > 11) { value["K"] = H - 12; } else { value["K"] = H; }
        value["k"] = H + 1;
        value["KK"] = LZ(value["K"]);
        value["kk"] = LZ(value["k"]);
        if (H > 11) { value["a"] = "PM"; }
        else { value["a"] = "AM"; }
        value["m"] = m;
        value["mm"] = LZ(m);
        value["s"] = s;
        value["ss"] = LZ(s);
        while (i_format < format.length) {
            c = format.charAt(i_format);
            token = "";
            while ((format.charAt(i_format) == c) && (i_format < format.length)) {
                token += format.charAt(i_format++);
            }
            if (value[token] != null) { result += value[token]; }
            else { result += token; }
        }
        return result;
    }

    function _isInteger(val) {
        return (new RegExp(/^\d+$/).test(val));
    }
    function _getInt(str, i, minlength, maxlength) {
        for (var x = maxlength; x >= minlength; x--) {
            var token = str.substring(i, i + x);
            if (token.length < minlength) { return null; }
            if (_isInteger(token)) { return token; }
        }
        return null;
    }

    /**
    * parseDate( date_string , format_string )
    * 
    * This function takes a date string and a format string. It matches
    * If the date string matches the format string, it returns the date. 
    * If it does not match, it returns 0.
    * @param {Object} val
    * @param {Object} format
    */
    function parseDate(val, format) {
        val = val + "";
        format = format + "";
        var i_val = 0;
        var i_format = 0;
        var c = "";
        var token = "";
        var token2 = "";
        var x, y;
        var now = new Date(1900, 0, 1);
        var year = now.getYear();
        var month = now.getMonth() + 1;
        var date = 1;
        var hh = now.getHours();
        var mm = now.getMinutes();
        var ss = now.getSeconds();
        var ampm = "";

        while (i_format < format.length) {
            // Get next token from format string
            c = format.charAt(i_format);
            token = "";
            while ((format.charAt(i_format) == c) && (i_format < format.length)) {
                token += format.charAt(i_format++);
            }
            // Extract contents of value based on format token
            if (token == "yyyy" || token == "yy" || token == "y") {
                if (token == "yyyy") { x = 4; y = 4; }
                if (token == "yy") { x = 2; y = 2; }
                if (token == "y") { x = 2; y = 4; }
                year = _getInt(val, i_val, x, y);
                if (year == null) { return 0; }
                i_val += year.length;
                if (year.length == 2) {
                    if (year > 70) { year = 1900 + (year - 0); }
                    else { year = 2000 + (year - 0); }
                }
            } else if (token == "MMM" || token == "NNN") {
                month = 0;
                for (var i = 0; i < MONTH_NAMES.length; i++) {
                    var month_name = MONTH_NAMES[i];
                    if (val.substring(i_val, i_val + month_name.length).toLowerCase() == month_name.toLowerCase()) {
                        if (token == "MMM" || (token == "NNN" && i > 11)) {
                            month = i + 1;
                            if (month > 12) { month -= 12; }
                            i_val += month_name.length;
                            break;
                        }
                    }
                }
                if ((month < 1) || (month > 12)) { return 0; }
            } else if (token == "EE" || token == "E") {
                for (var i = 0; i < DAY_NAMES.length; i++) {
                    var day_name = DAY_NAMES[i];
                    if (val.substring(i_val, i_val + day_name.length).toLowerCase() == day_name.toLowerCase()) {
                        i_val += day_name.length;
                        break;
                    }
                }
            } else if (token == "MM" || token == "M") {
                month = _getInt(val, i_val, token.length, 2);
                if (month == null || (month < 1) || (month > 12)) { return 0; }
                i_val += month.length;
            } else if (token == "dd" || token == "d") {
                date = _getInt(val, i_val, token.length, 2);
                if (date == null || (date < 1) || (date > 31)) { return 0; }
                i_val += date.length;
            } else if (token == "hh" || token == "h") {
                hh = _getInt(val, i_val, token.length, 2);
                if (hh == null || (hh < 1) || (hh > 12)) { return 0; }
                i_val += hh.length;
            } else if (token == "HH" || token == "H") {
                hh = _getInt(val, i_val, token.length, 2);
                if (hh == null || (hh < 0) || (hh > 23)) { return 0; }
                i_val += hh.length;
            }
            else if (token == "KK" || token == "K") {
                hh = _getInt(val, i_val, token.length, 2);
                if (hh == null || (hh < 0) || (hh > 11)) { return 0; }
                i_val += hh.length;
            } else if (token == "kk" || token == "k") {
                hh = _getInt(val, i_val, token.length, 2);
                if (hh == null || (hh < 1) || (hh > 24)) { return 0; }
                i_val += hh.length; hh--;
            } else if (token == "mm" || token == "m") {
                mm = _getInt(val, i_val, token.length, 2);
                if (mm == null || (mm < 0) || (mm > 59)) { return 0; }
                i_val += mm.length;
            } else if (token == "ss" || token == "s") {
                ss = _getInt(val, i_val, token.length, 2);
                if (ss == null || (ss < 0) || (ss > 59)) { return 0; }
                i_val += ss.length;
            } else if (token == "a") {
                if (val.substring(i_val, i_val + 2).toLowerCase() == "am") { ampm = "AM"; }
                else if (val.substring(i_val, i_val + 2).toLowerCase() == "pm") { ampm = "PM"; }
                else { return 0; }
                i_val += 2;
            } else {
                if (val.substring(i_val, i_val + token.length) != token) { return 0; }
                else { i_val += token.length; }
            }
        }
        // If there are any trailing characters left in the value, it doesn't match
        if (i_val != val.length) { return 0; }
        // Is date valid for month?
        if (month == 2) {
            // Check for leap year
            if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) { // leap year
                if (date > 29) { return 0; }
            } else { if (date > 28) { return 0; } }
        }
        if ((month == 4) || (month == 6) || (month == 9) || (month == 11)) {
            if (date > 30) { return 0; }
        }
        // Correct hours value
        if (hh < 12 && ampm == "PM") { hh = hh - 0 + 12; }
        else if (hh > 11 && ampm == "AM") { hh -= 12; }
        return new Date(year, month - 1, date, hh, mm, ss);
    }

    Date.prototype.formatDate = function(dateFmt) {
        return formatDate(this, dateFmt);
    };
    String.prototype.parseDate = function(dateFmt) {
        if (this.length < dateFmt.length) {
            dateFmt = dateFmt.slice(0, this.length);
        }
        return parseDate(this, dateFmt);
    };

    Date.prototype.getDays = function() {
        var y, m;
        y = this.getFullYear();
        m = this.getMonth() + 1;
        //获取某年某月的天数
        return m == 2 ? (y % 4 || !(y % 100) && y % 400 ? 28 : 29) : (/4|6|9|11/.test(m) ? 30 : 31);
    };

    /**
    * replaceTmEval("{1+2}-{2-1}")
    */
    function replaceTmEval(data) {
        return data.replace(RegExp("({[A-Za-z0-9_+-]*})", "g"), function($1) {
            return eval('(' + $1.replace(/[{}]+/g, "") + ')');
        });
    }
    /**
    * dateFmt:%y-%M-%d
    * %y-%M-{%d+1}
    * ex: new Date().formatDateTm('%y-%M-{%d-1}')
    * 	new Date().formatDateTm('2012-1')
    */
    Date.prototype.formatDateTm = function(dateFmt) {
        var y = this.getFullYear();
        var m = this.getMonth() + 1;
        var d = this.getDate();

        var sDate = dateFmt.replaceAll("%y", y).replaceAll("%M", m).replaceAll("%d", d);
        sDate = replaceTmEval(sDate);

        var _y = 1900, _m = 0, _d = 1;
        var aDate = sDate.split('-');

        if (aDate.length > 0) _y = aDate[0];
        if (aDate.length > 1) _m = aDate[1] - 1;
        if (aDate.length > 2) _d = aDate[2];

        return new Date(_y, _m, _d).formatDate('yyyy-MM-dd');
    };

    String.prototype.IsValidDate = function() {
        try {
            return this.parseDate("yyyy-M-d") != 0;
        }
        catch (e) {
            return false;
        }
    };

})();
